﻿// Type definitions for QUnit 1.10
// Project: http://qunitjs.com/
// Definitions by: Diullei Gomes <https://github.com/diullei>
// DefinitelyTyped: https://github.com/borisyankov/DefinitelyTyped


interface DoneCallbackObject {
    /**
    * The number of failed assertions
    */
    failed: number;

    /**
    * The number of passed assertions
    */
    passed: number;

    /**
    * The total number of assertions
    */
    total: number;

    /**
    * The time in milliseconds it took tests to run from start to finish.
    */
    runtime: number;
}

interface LogCallbackObject {
    /**
    * The boolean result of an assertion, true means passed, false means failed.
    */
    result: bool;

    /**
    * One side of a comparision assertion. Can be undefined when ok() is used.
    */
    actual: Object;

    /**
    * One side of a comparision assertion. Can be undefined when ok() is used.
    */
    expected: Object;

    /**
    * A string description provided by the assertion.
    */
    message: string;

    /**
    * The associated stacktrace, either from an exception or pointing to the source
    * of the assertion. Depends on browser support for providing stacktraces, so can be
    * undefined.
    */
    source: string;
}

interface ModuleStartCallbackObject {
    /**
    * Name of the next module to run
    */
    name: string;
}

interface ModuleDoneCallbackObject {
    /**
    * Name of this module
    */
    name: string;

    /**
    * The number of failed assertions
    */
    failed: number;

    /**
    * The number of passed assertions
    */
    passed: number;

    /**
    * The total number of assertions
    */
    total: number;
}

interface TestDoneCallbackObject {
    /**
    * TName of the next test to run
    */
    name: string;

    /**
    * Name of the current module
    */
    module: string;

    /**
    * The number of failed assertions
    */
    failed: number;

    /**
    * The number of passed assertions
    */
    passed: number;

    /**
    * The total number of assertions
    */
    total: number;

    /**
    * The total runtime, including setup and teardown
    */
    duration: number;
}

interface TestStartCallbackObject {
    /**
    * Name of the next test to run
    */
    name: string;

    /**
    * Name of the current module
    */
    module: string;
}

interface Config {
    altertitle: bool;
    autostart: bool;
    current: Object;
    reorder: bool;
    requireExpects: bool;
    urlConfig: Array;
    done: any;
}

interface LifecycleObject {
    /**
    * Runs before each test
    */
    setup?: () => any;

    /**
    * Runs after each test
    */
    teardown?: () => any;
}

interface QUnitAssert {
    /* ASSERT */
    assert: any;
    current_testEnvironment: any;
    jsDump: any;

    /**
    * A deep recursive comparison assertion, working on primitive types, arrays, objects,
    * regular expressions, dates and functions.
    *
    * The deepEqual() assertion can be used just like equal() when comparing the value of
    * objects, such that { key: value } is equal to { key: value }. For non-scalar values,
    * identity will be disregarded by deepEqual.
    *
    * @param actual Object or Expression being tested
    * @param expected Known comparison value
    * @param message A short description of the assertion
    */
    deepEqual(actual: any, expected: any, message?: string);

    /**
    * A non-strict comparison assertion, roughly equivalent to JUnit assertEquals.
    *
    * The equal assertion uses the simple comparison operator (==) to compare the actual
    * and expected arguments. When they are equal, the assertion passes; otherwise, it fails.
    * When it fails, both actual and expected values are displayed in the test result,
    * in addition to a given message.
    *
    * @param actual Expression being tested
    * @param expected Known comparison value
    * @param message A short description of the assertion
    */
    equal(actual: any, expected: any, message?: string);

    /**
    * An inverted deep recursive comparison assertion, working on primitive types,
    * arrays, objects, regular expressions, dates and functions.
    *
    * The notDeepEqual() assertion can be used just like equal() when comparing the
    * value of objects, such that { key: value } is equal to { key: value }. For non-scalar
    * values, identity will be disregarded by notDeepEqual.
    *
    * @param actual Object or Expression being tested
    * @param expected Known comparison value
    * @param message A short description of the assertion
    */
    notDeepEqual(actual: any, expected: any, message?: string);

    /**
    * A non-strict comparison assertion, checking for inequality.
    *
    * The notEqual assertion uses the simple inverted comparison operator (!=) to compare
    * the actual and expected arguments. When they aren't equal, the assertion passes;
    * otherwise, it fails. When it fails, both actual and expected values are displayed
    * in the test result, in addition to a given message.
    *
    * @param actual Expression being tested
    * @param expected Known comparison value
    * @param message A short description of the assertion
    */
    notEqual(actual: any, expected: any, message?: string);

    notPropEqual(actual: any, expected: any, message?: string);

    propEqual(actual: any, expected: any, message?: string);

    /**
    * A non-strict comparison assertion, checking for inequality.
    *
    * The notStrictEqual assertion uses the strict inverted comparison operator (!==)
    * to compare the actual and expected arguments. When they aren't equal, the assertion
    * passes; otherwise, it fails. When it fails, both actual and expected values are
    * displayed in the test result, in addition to a given message.
    *
    * @param actual Expression being tested
    * @param expected Known comparison value
    * @param message A short description of the assertion
    */
    notStrictEqual(actual: any, expected: any, message?: string);

    /**
    * A boolean assertion, equivalent to CommonJS’s assert.ok() and JUnit’s assertTrue().
    * Passes if the first argument is truthy.
    *
    * The most basic assertion in QUnit, ok() requires just one argument. If the argument
    * evaluates to true, the assertion passes; otherwise, it fails. If a second message
    * argument is provided, it will be displayed in place of the result.
    *
    * @param state Expression being tested
    * @param message A short description of the assertion
    */
    ok(state: any, message?: string);

    /**
    * A strict type and value comparison assertion.
    *
    * The strictEqual() assertion provides the most rigid comparison of type and value with
    * the strict equality operator (===)
    *
    * @param actual Expression being tested
    * @param expected Known comparison value
    * @param message A short description of the assertion
    */
    strictEqual(actual: any, expected: any, message?: string);

    /**
    * Assertion to test if a callback throws an exception when run.
    *
    * When testing code that is expected to throw an exception based on a specific set of
    * circumstances, use throws() to catch the error object for testing and comparison.
    *
    * @param block Function to execute
    * @param expected Error Object to compare
    * @param message A short description of the assertion
    */
    throws(block: () => any, expected: any, message?: string);

    /**
    * @param block Function to execute
    * @param message A short description of the assertion
    */
    throws(block: () => any, message?: string);
}

interface QUnitStatic extends QUnitAssert {
    /* ASYNC CONTROL */

    /**
    * Start running tests again after the testrunner was stopped. See stop().
    *
    * When your async test has multiple exit points, call start() for the corresponding number of stop() increments.
    *
    * @param decrement Optional argument to merge multiple start() calls into one. Use with multiple corrsponding stop() calls.
    */
    start(decrement?: number);

    /**
    * Stop the testrunner to wait for async tests to run. Call start() to continue.
    *
    * When your async test has multiple exit points, call stop() with the increment argument, corresponding to the number of start() calls you need.
    *
    * On Blackberry 5.0, window.stop is a native read-only function. If you deal with that browser, use QUnit.stop() instead, which will work anywhere.
    *
    * @param decrement Optional argument to merge multiple stop() calls into one. Use with multiple corrsponding start() calls.
    */
    stop(increment?: number);

    /* CALLBACKS */

    /**
    * Register a callback to fire whenever the test suite begins.
    *
    * QUnit.begin() is called once before running any tests. (a better would've been QUnit.start,
    * but thats already in use elsewhere and can't be changed.)
    *
    * @param callback Callback to execute
    */
    begin(callback: () => any);

    /**
    * Register a callback to fire whenever the test suite ends.
    *
    * @param callback Callback to execute.
    */
    done(callback: (details: DoneCallbackObject) => any);

    /**
    * Register a callback to fire whenever an assertion completes.
    *
    * This is one of several callbacks QUnit provides. Its intended for integration scenarios like
    * PhantomJS or Jenkins. The properties of the details argument are listed below as options.
    *
    * @param callback Callback to execute.
    */
    log(callback: (details: LogCallbackObject) => any);

    /**
    * Register a callback to fire whenever a module ends.
    *
    * @param callback Callback to execute.
    */
    moduleDone(callback: (details: ModuleDoneCallbackObject) => any);

    /**
    * Register a callback to fire whenever a module begins.
    *
    * @param callback Callback to execute.
    */
    moduleStart(callback: (details: ModuleStartCallbackObject) => any);

    /**
    * Register a callback to fire whenever a test ends.
    *
    * @param callback Callback to execute.
    */
    testDone(callback: (details: TestDoneCallbackObject) => any);

    /**
    * Register a callback to fire whenever a test begins.
    *
    * @param callback Callback to execute.
    */
    testStart(callback: (details: TestStartCallbackObject) => any);

    /* CONFIGURATION */

    /**
    * QUnit has a bunch of internal configuration defaults, some of which are
    * useful to override. Check the description for each option for details.
    */
    config: Config;

    /* TEST */

    /**
    * Add an asynchronous test to run. The test must include a call to start().
    *
    * For testing asynchronous code, asyncTest will automatically stop the test runner
    * and wait for your code to call start() to continue.
    *
    * @param name Title of unit being tested
    * @param expected Number of assertions in this test
    * @param test Function to close over assertions
    */
    asyncTest(name: string, expected: number, test: () => any);

    /**
    * Add an asynchronous test to run. The test must include a call to start().
    *
    * For testing asynchronous code, asyncTest will automatically stop the test runner
    * and wait for your code to call start() to continue.
    *
    * @param name Title of unit being tested
    * @param test Function to close over assertions
    */
    asyncTest(name: string, test: () => any);

    /**
    * Specify how many assertions are expected to run within a test.
    *
    * To ensure that an explicit number of assertions are run within any test, use
    * expect( number ) to register an expected count. If the number of assertions
    * run does not match the expected count, the test will fail.
    *
    * @param amount Number of assertions in this test.
    */
    expect(amount: number);

    /**
    * Group related tests under a single label.
    *
    * All tests that occur after a call to module() will be grouped into that module.
    * The test names will all be preceded by the module name in the test results.
    * You can then use that module name to select tests to run.
    *
    * @param name Label for this group of tests
    * @param lifecycle Callbacks to run before and after each test
    */
    module(name: string, lifecycle?: LifecycleObject);

    /**
    * Add a test to run.
    *
    * When testing the most common, synchronous code, use test().
    * The assert argument to the callback contains all of QUnit's assertion methods.
    * If you are avoiding using any of QUnit's globals, you can use the assert
    * argument instead.
    *
    * @param title Title of unit being tested
    * @param expected Number of assertions in this test
    * @param test Function to close over assertions
    */
    test(title: string, expected: number, test: (assert: QUnitAssert) => any);

    /**
    * @param title Title of unit being tested
    * @param test Function to close over assertions
    */
    test(title: string, test: (assert: QUnitAssert) => any);

    /**
    * https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L1568
    */
    equiv(a: any, b: any);

    // https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L661
    raises: any;

    /**
    * https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L897
    */
    push(result, actual, expected, message): any;

    /**
    * https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L839
    */
    reset(): any;
}

/* ASSERT */

/**
* A deep recursive comparison assertion, working on primitive types, arrays, objects,
* regular expressions, dates and functions.
*
* The deepEqual() assertion can be used just like equal() when comparing the value of
* objects, such that { key: value } is equal to { key: value }. For non-scalar values,
* identity will be disregarded by deepEqual.
*
* @param actual Object or Expression being tested
* @param expected Known comparison value
* @param message A short description of the assertion
*/
declare function deepEqual(actual: any, expected: any, message?: string);

/**
* A non-strict comparison assertion, roughly equivalent to JUnit assertEquals.
*
* The equal assertion uses the simple comparison operator (==) to compare the actual
* and expected arguments. When they are equal, the assertion passes; otherwise, it fails.
* When it fails, both actual and expected values are displayed in the test result,
* in addition to a given message.
*
* @param actual Expression being tested
* @param expected Known comparison value
* @param message A short description of the assertion
*/
declare function equal(actual: any, expected: any, message?: string);

/**
* An inverted deep recursive comparison assertion, working on primitive types,
* arrays, objects, regular expressions, dates and functions.
*
* The notDeepEqual() assertion can be used just like equal() when comparing the
* value of objects, such that { key: value } is equal to { key: value }. For non-scalar
* values, identity will be disregarded by notDeepEqual.
*
* @param actual Object or Expression being tested
* @param expected Known comparison value
* @param message A short description of the assertion
*/
declare function notDeepEqual(actual: any, expected: any, message?: string);

/**
* A non-strict comparison assertion, checking for inequality.
*
* The notEqual assertion uses the simple inverted comparison operator (!=) to compare
* the actual and expected arguments. When they aren't equal, the assertion passes;
* otherwise, it fails. When it fails, both actual and expected values are displayed
* in the test result, in addition to a given message.
*
* @param actual Expression being tested
* @param expected Known comparison value
* @param message A short description of the assertion
*/
declare function notEqual(actual: any, expected: any, message?: string);

/**
* A non-strict comparison assertion, checking for inequality.
*
* The notStrictEqual assertion uses the strict inverted comparison operator (!==)
* to compare the actual and expected arguments. When they aren't equal, the assertion
* passes; otherwise, it fails. When it fails, both actual and expected values are
* displayed in the test result, in addition to a given message.
*
* @param actual Expression being tested
* @param expected Known comparison value
* @param message A short description of the assertion
*/
declare function notStrictEqual(actual: any, expected: any, message?: string);

/**
* A boolean assertion, equivalent to CommonJS’s assert.ok() and JUnit’s assertTrue().
* Passes if the first argument is truthy.
*
* The most basic assertion in QUnit, ok() requires just one argument. If the argument
* evaluates to true, the assertion passes; otherwise, it fails. If a second message
* argument is provided, it will be displayed in place of the result.
*
* @param state Expression being tested
* @param message A short description of the assertion
*/
declare function ok(state: any, message?: string);

/**
* A strict type and value comparison assertion.
*
* The strictEqual() assertion provides the most rigid comparison of type and value with
* the strict equality operator (===)
*
* @param actual Expression being tested
* @param expected Known comparison value
* @param message A short description of the assertion
*/
declare function strictEqual(actual: any, expected: any, message?: string);

/**
* Assertion to test if a callback throws an exception when run.
*
* When testing code that is expected to throw an exception based on a specific set of
* circumstances, use throws() to catch the error object for testing and comparison.
*
* @param block Function to execute
* @param expected Error Object to compare
* @param message A short description of the assertion
*/
declare function throws(block: () => any, expected: any, message?: string);

/**
* @param block Function to execute
* @param message A short description of the assertion
*/
declare function throws(block: () => any, message?: string);

/* ASYNC CONTROL */

/**
* Start running tests again after the testrunner was stopped. See stop().
*
* When your async test has multiple exit points, call start() for the corresponding number of stop() increments.
*
* @param decrement Optional argument to merge multiple start() calls into one. Use with multiple corrsponding stop() calls.
*/
declare function start(decrement?: number);

/**
* Stop the testrunner to wait for async tests to run. Call start() to continue.
*
* When your async test has multiple exit points, call stop() with the increment argument, corresponding to the number of start() calls you need.
*
* On Blackberry 5.0, window.stop is a native read-only function. If you deal with that browser, use QUnit.stop() instead, which will work anywhere.
*
* @param decrement Optional argument to merge multiple stop() calls into one. Use with multiple corrsponding start() calls.
*/
declare function stop(increment?: number);

/* CALLBACKS */

/**
* Register a callback to fire whenever the test suite begins.
*
* QUnit.begin() is called once before running any tests. (a better would've been QUnit.start,
* but thats already in use elsewhere and can't be changed.)
*
* @param callback Callback to execute
*/
declare function begin(callback: () => any);

/**
* Register a callback to fire whenever the test suite ends.
*
* @param callback Callback to execute.
*/
declare function done(callback: (details: DoneCallbackObject) => any);

/**
* Register a callback to fire whenever an assertion completes.
*
* This is one of several callbacks QUnit provides. Its intended for integration scenarios like
* PhantomJS or Jenkins. The properties of the details argument are listed below as options.
*
* @param callback Callback to execute.
*/
declare function log(callback: (details: LogCallbackObject) => any);

/**
* Register a callback to fire whenever a module ends.
*
* @param callback Callback to execute.
*/
declare function moduleDone(callback: (details: ModuleDoneCallbackObject) => any);

/**
* Register a callback to fire whenever a module begins.
*
* @param callback Callback to execute.
*/
declare function moduleStart(callback: (name: string) => any);

/**
* Register a callback to fire whenever a test ends.
*
* @param callback Callback to execute.
*/
declare function testDone(callback: (details: TestDoneCallbackObject) => any);

/**
* Register a callback to fire whenever a test begins.
*
* @param callback Callback to execute.
*/
declare function testStart(callback: (details: TestStartCallbackObject) => any);

/* TEST */

/**
* Add an asynchronous test to run. The test must include a call to start().
*
* For testing asynchronous code, asyncTest will automatically stop the test runner
* and wait for your code to call start() to continue.
*
* @param name Title of unit being tested
* @param expected Number of assertions in this test
* @param test Function to close over assertions
*/
declare function asyncTest(name: string, expected?: any, test?: () => any);

/**
* Add an asynchronous test to run. The test must include a call to start().
*
* For testing asynchronous code, asyncTest will automatically stop the test runner
* and wait for your code to call start() to continue.
*
* @param name Title of unit being tested
* @param test Function to close over assertions
*/
declare function asyncTest(name: string, test: () => any);

/**
* Specify how many assertions are expected to run within a test.
*
* To ensure that an explicit number of assertions are run within any test, use
* expect( number ) to register an expected count. If the number of assertions
* run does not match the expected count, the test will fail.
*
* @param amount Number of assertions in this test.
*/
declare function expect(amount: number);

// ** conflict with TypeScript module keyword. Must be used on QUnit namespace
//declare var module: (name: string, lifecycle?: LifecycleObject) => any;

/**
* Add a test to run.
*
* When testing the most common, synchronous code, use test().
* The assert argument to the callback contains all of QUnit's assertion methods.
* If you are avoiding using any of QUnit's globals, you can use the assert
* argument instead.
*
* @param title Title of unit being tested
* @param expected Number of assertions in this test
* @param test Function to close over assertions
*/
declare function test(title: string, expected: number, test: (assert?: QUnitAssert) => any);

/**
* @param title Title of unit being tested
* @param test Function to close over assertions
*/
declare function test(title: string, test: (assert?: QUnitAssert) => any);

declare function notPropEqual(actual: any, expected: any, message?: string);

declare function propEqual(actual: any, expected: any, message?: string);

// https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L1568
declare function equiv(a: any, b: any);

// https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L661
declare var raises: any;

/* QUNIT */
declare var QUnit: QUnitStatic;